#include "thread/thread.h"
#include <memory>
#include <thread>
#include <mutex>

class ThreadData
{
public:
    explicit ThreadData(Thread *thread);
private:
    friend class Thread;
    Thread *thread_ptr;
    std::unique_ptr<std::thread> thread;
    std::mutex mutex;
    bool running{false};
    std::string thread_name;

private:
    void start();

    void finish();
};
ThreadData::ThreadData(Thread *thread)
    : thread_ptr(thread)
{
}
void ThreadData::start()
{
    if (!thread_name.empty())
    {
        pthread_setname_np(pthread_self(), thread_name.c_str());
    }
    thread_ptr->run();
    finish();
}
void ThreadData::finish()
{
    running = false;
}

Thread::Thread()
    : data_(std::make_unique<ThreadData>(this))
{
}
Thread::Thread(const std::string &thread_name)
    : data_(std::make_unique<ThreadData>(this))
{
    data_->thread_name = thread_name;
}
Thread::~Thread() = default;

void Thread::start()
{
    std::lock_guard<std::mutex> locker(data_->mutex);

    if (data_->running)
    {
        fprintf(stderr, "current thread is running, cannot start\n");
        return;
    }

    data_->running = true;

    data_->thread = std::make_unique<std::thread>(&ThreadData::start, data_.get());
    data_->thread->detach();
}
bool Thread::isRunning() const
{
    return data_->running;
}
void Thread::setThreadName(const std::string &thread_name)
{
    data_->thread_name = thread_name;
}
std::string Thread::getThreadName() const
{
    return data_->thread_name;
}
unsigned long int Thread::currentThreadId() noexcept
{
    return pthread_self();
}
void Thread::sleep(unsigned long secs)
{
    std::this_thread::sleep_for(std::chrono::seconds(secs));
}
void Thread::msleep(unsigned long msecs)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(msecs));
}
void Thread::usleep(unsigned long usecs)
{
    std::this_thread::sleep_for(std::chrono::microseconds(usecs));
}

